Welcome back.
In this lecture we're going to be learning about a fundamental feature in Roblox studio called Ray casting.
Ray casting is this idea of shooting an invisible ray in a defined direction with a defined distance,
and checking to see if that ray hit any 3D object in our workspace.
To be able to perform a raycast, we first need an origin point and a direction that defines where we
want to shoot a ray from with respect to that origin point.
A cool way for us to demonstrate Raycasting would be creating a simple tool, and every time the player
clicks the tool, we're going to fire a ray pointing towards wherever that tool is looking, and then
we'll check to see if that ray hits any object in our workspace.
So we're going to create a new tool in the starter pack.
And I'm just going to call this tool Raycast tool.
And then for the handle for this tool, I'll just create a new part inside of my tool.
I'll call it handle and I'm going to make it a little bit smaller.
So I'll just uh, I'll just have the dimensions be a cube of 0.5 by 0.5 by 0.5 studs, and then we'll
make sure can collide is turned off for this handle.
And we'll make sure it's unanchored as well.
And then inside of here we can go ahead and create a server script to listen to the events for this
tool.
So I'll make a reference to my tool.
Create a variable called tool.
And that's just equal to script dot parent.
And then I'll also make a reference to my handle and let's say child of my tool.
And then what we could do is when the tool is activated by a player, we can go ahead and shoot a ray
in the direction of wherever our handle is facing in our tool.
To fire a ray.
In our game, we use a function underneath the workspace of raycast and as you can see it says this
function takes an origin point, a direction as well as some optional raycast parameters, and it says
casts a ray using an origin direction and an optional raycast parameters.
Then returns a raycast result if an eligible object or terrain intersects the ray.
Here in the Roblox documentation, we can see that a raycast result is a custom data type, and it says.
This data type stores the result of successful Raycasting operation performed by World Route, which
would be the workspace and the raycast function.
And inside of this data type it stores some properties such as the distance it says, the distance between
the ray origin and the intersection point, the instance that was hit.
So that would be the base part or the terrain that the ray intersected.
There would be the material at the intersection point.
It gives us the position where this ray hit an object, as well as the normal and the normal vector
of the intersected face.
And the normal vector is basically just what direction is forward for whatever part's face it hit.
So if it hit one side of a part, then the normal or the direction that that face is looking towards
would be this normal property right here.
We can also go ahead and take a look at the raycast parameter data type and it says the raycast parameter.
Data type stores parameters for the raycast function and it has some properties down here.
This is an array called Filter Descendants instances, and we would pass a table or an array of objects
whose descendants are used in filtering raycast candidates, and we choose this by setting the filter
type with an enum raycast filter type.
So we would either include or exclude these certain objects from the raycast operation if we include
them.
That means this raycast is going to ignore every single object in our game, except for the objects
within our filter descendants instances array.
And if we set the filter type to exclude, then the raycast is going to include every object in our
game except for the objects that are inside of this array.
We also have some additional properties here, such as.
If we would like the ray to ignore water.
We can also set a collision group that we would like the raycast to include or exclude.
There's another property here called respect can Collide and it says determines whether the raycast
operation considers a parts can collide property over its can query value.
And every single part in your game has this property called can query.
And this property allows you to basically select which parts in your game are included or excluded in
raycast operations.
Any parts in your game that have the can query property set to false will not be included in any raycast.
And then this last one here is called Brute Force.
All slow and it says when enabled, the query will ignore all part collision properties and perform
a brute force check on every single part.
Back in studio.
Whenever our player activates this tool, we want to go ahead and shoot a ray from an origin point,
which would be the position of our handle in a direction which would be wherever our handle is facing.
So we can call our raycast function.
And that means we need to pass the origin direction and optional raycast parameters.
So let's go ahead and create two variables.
One variable is going to be my origin, while the other variable is going to be my direction.
So for the origin this one's going to be very simple.
The origin is going to be my handles position in the workspace.
So we just get handle dot position.
This is where we would like the ray to start at.
And then the direction is going to be whichever way our handle is facing.
And to get the look vector of our handle we can reference our handle keyframe.
And our keyframe stores the look vector property.
And that returns the forward direction component of the keyframe object's orientation.
So this will basically tell us where our part is looking as an example.
If we take a look at this part right here, and we right click our part and we press Show Orientation
indicator here, it shows us the look vector for this part, which is on this front facing side of our
part.
And that is the direction or the look vector for this part.
Now that we have our origin and our direction, we can go ahead and pass the origin and then we can
also pass the direction.
Now this direction also needs to include a length or a magnitude.
And as you can see it says note that the length of this vector matters as part trains further away than
its length will not be tested.
So this is where you would multiply this vector by a value, which would indicate how long you would
like this direction to be.
For example, if I multiplied this direction by the value of ten, then my direction is going to be
ten studs in length.
So this is going to fire a ray up to ten studs away from me, and then it's going to stop and ignore
anything else further away.
If I want it to shoot farther than that, I could enter a value like 500.
And now my direction is going to basically fire a ray 500 studs away from me, and this ray will stop
once it hits a part in our workspace.
So for this demonstration, we'll just put it at 100 studs.
And of course this function is going to return to us a raycast result.
So we'll create a variable and we'll just call it result.
Now we're also going to go ahead and take a look at raycast parameters.
So outside of my activated event I'm going to create a variable called params.
And that's going to be equal to a new raycast parameter.
So we refer to raycast params.
And then to create one we use the new constructor.
And then from here we have access to all of those different properties inside of this data type, such
as filter descendant instances, the filter type and some other settings as well.
If we would like to exclude some different items from our raycast and we can set the filter type equal
to the enum dot raycast filter type dot exclude.
This used to be blacklist, but for some reason they deprecated it.
As you can see it is um.
Has a strike through through it.
So that means it's deprecated.
I don't know why they deprecated Blacklist and Whitelist and replaced it with exclude and include,
but it's whatever.
So we use exclude now instead of blacklist.
Then every time we activate the tool, some things that we want to go ahead and ignore from this raycast
would be for example, our player's character.
We don't want to intersect with anything on our player's character, and we certainly don't want to
intersect with the handle that the ray is going to be firing from, because that'd be kind of stupid.
So what we can do is we can go ahead and update the parameters dot filter, descendent instances equal
to a new table.
And this table is going to contain the parent of our tool.
And since this tool can only be activated when it's equipped, that means the parent of our tool is
going to be a player's character model.
And that character model includes this tool.
So this tool is going to be exempt from our raycast as well as any descendants or 3D object descendants
of our player's character.
Now we can go ahead and pass our raycast parameters to our raycast function to be included in our raycast
operation.
Now this is going to fire a ray inside of our workspace, and it's going to check to see if it hits
anything.
And that's going to be returned in this raycast result.
So we can go ahead and check if this function actually returns something.
Because if this raycast didn't hit anything, then the function is going to return nil.
So we can check to see if we hit something by checking to see if there's a value stored in result.
And if there is, then we can go ahead and print that.
We hit an instance.
And this result of course stores some information, for example, the instance that we hit.
So we can get the instance and then the name of the instance.
So we can print that we hit this particular instance.
And then we can also print out what position we hit this instance.
So I'll say at position.
And then we can pass the results dot position.
Otherwise, if there is no result, that means our raycast did not find any 3D objects in our workspace
to hit, so we can print something like the ray hit nothing.
So now let's go ahead and playtest our game and see what happens.
So here is my raycast tool and my part.
And this should shoot a ray out from this face of my part in that direction.
100 studs.
If it hits anything then it'll print what it hit, otherwise it should print nothing.
So if I turn and face this part and then I were to click.
As you can see, it says we hit an instance part at position, and then it gives us the exact position
where the ray intersected with the part.
We can also click over here or click here.
But if we face away from our part and then we shoot, as you can see, the ray hit nothing because there's
nothing in front of us for the ray to intersect.
Now we can also go ahead and visualize this raycast by creating a part, and then positioning that part
between our origin point and the hit point, and then increasing the length of our part to represent
the total distance of the raycast.
So let's go ahead and do that.
If we get a result from our raycast, then what we can do is we can create a new part.
And the size of this part is going to be equal to a new vector three and for the x size, we need it
to be 0.05.
And for the y size we also need it to be 0.05.
And the z is going to be the length or the distance between the origin point and the hit point from
our result data type here.
So this is going to be equal to the result dot distance.
And the reason we have to do it on the Z axis is that if we take a look and we create a new part here.
And we were to show the orientation indicator.
So this is the front of my part.
And if we were to resize this part, as you can see, the area we need to resize is the z axis when
this part faces an object.
And that's because we need to set the keyframe of this part to be facing towards wherever we hit, and
that way it's accurate and it looks correct.
So if we were to set the size to be 0.05 and 0.05 and then like ten, then this is what our array is
going to look at.
And this part is basically going to visualize where our ray hit in the workspace.
It's going to look towards where we hit and it's going to orient itself correctly.
We can imagine this end as the origin point and this end as the point of where we intersected a part.
This is what our array is going to look like.
Once we set the size, we can go ahead and change the color.
I'll just make it completely white.
So we'll do from RGB and we'll create.
It's already white.
So we'll just do that.
We'll make sure the part is anchored.
And we'll also make sure that can collide is false.
So we don't hit it.
And now we need to go ahead and update the keyframe of our part.
And this is going to be simple.
All we need to do is use the keyframe dot lookup function.
And remember this returns a keyframe with a position of the first vector and an orientation pointed
towards the second.
So we're basically positioning this part to be at the origin, and we want it to look at wherever we
hit, which would be the result dot position.
So now our part is going to be looking towards this position from the origin point.
Now, since the pivot of our part is directly in the center, for example, that is our central pivot
point of the part.
It's not at the end or over here.
That means we need to account for the fact that the pivot is in the center of our part.
So we need to move this part by half of the distance.
So that way it's perfectly positioned between the origin point and the point at where we hit.
To visualize this, you can basically think of this black dot right here as our player.
And then this red dot is our origin point.
And this other red dot is where we hit.
And you can imagine this as another part.
So the player fired a ray towards this direction.
And we hit right here.
And we want to get the position between these two points the half way mark.
So that way we can accurately set the keyframe of our part to be perfectly between these two parts.
If we didn't account for this offset, then our part would instead look something like this, where
the central point of our part would be next to our origin point, it would look incorrect, so we need
to offset it by whatever half the distance is between our origin point and our hit point.
And that's very easy to do as well.
All we need to do is add a new keyframe and remember to add a keyframe to another keyframe.
We have to use the multiplication symbol and not the addition symbol.
The addition symbol is when you offset it using vectors, and then the multiplication symbol is when
we offset it with another keyframe.
So we'll create another new keyframe here.
We don't need to offset it on the x axis or the z axis, but we need to offset it on the z axis, because
that's the direction where the look vector is.
And that z offset, remember, is going to be half the distance of result dot distance.
So we'll just pass result dot distance and then divide it by two.
And then in order to make sure that this offsets in the correct direction we actually need to negate
this value.
So basically shifting the position of this part.
From the origin point to the point between the origin and the position of where we hit.
And then once we do that, we can finally set the parent of our part equal to the workspace so we can
actually see it in our game.
So now if we go and play test.
If I were to look away and I clicked.
As you can see, the ray hit nothing.
But if I turn around and look at my part and then I click.
As you can see now we have visualized this raycast with this custom part right here.
This was my origin point and the ray fired in this direction and kept going until it hit my part.
And that's where this part ends, right?
So that is the total distance between the origin point and the point at which we hit.
And of course, we can keep shooting these rays out and keep firing them and keep visualizing them.
And those are all of the ray casts that are being shot out from my origin point, and hitting this part
right here.
And of course, I can't hit anything that is not in front of me.
But if I walk, you can see that the origin point is moving up and down.
And then if I click, as you can see, the look vector of this part is pointed downwards as I walk.
So we're hitting the base plate now.
One more thing before I let you go, let's go ahead and take a look at the Cam query property.
For parts.
To access the can query property, we have to go down to the collision section and the properties panel
for this part.
And in order to see the can query property we have to go ahead and disable can collide.
Once we disable can collide then the can query property shows up.
And this will determine whether or not this part is going to be involved in any spatial queries in the
game, including Raycasts.
So if I disable this property and then we go and playtest our game, now when I go and click my tool
to try and fire a ray at this part, it's not going to intersect anything.
So if I hold out my tool and then I click.
As you can see, this part is now being excluded from that raycast operation.
And it's telling us that the ray hit nothing.
I can keep clicking and keep clicking, and no matter what, the ray is going to permanently ignore
this part.
So this is how we can visualize Raycasts.
And this is also how we can use Raycasts to detect when we hit parts or 3D objects in our game.
That's all for me for this lecture.
I hope you enjoyed and I'll see you in the next one.